Ben Rosenberg

# Custom Functions

getPop = function(schoolnameV, yearV) {
  n = yearV-2011
  converter = list()
  converter[["Macalester"]] = "Macalester College"
  converter[["HU"]] =  "Hamline University"
  converter[["St. Olaf"]] = "St Olaf College"
  converter[["Gustavus"]] =  "Gustavus Adolphus College"
  converter[["Bethel"]] = "Bethel University"
  converter[["Augsburg"]] =  "Augsburg University"
  converter[["Carleton"]] =  "Carleton College"
  converter[["St. Benedict"]] = "College of Saint Benedict"
  converter[["Concordia"]] = "Concordia University-Saint Paul"
  converter[["St. John"]] = "Saint Johns University"
  converter[["St. Scholastica"]] = "The College of Saint Scholastica"
  converter[["St. Kate"]] ="St Catherine University"
  converter[["St. Mary"]] ="Saint Mary's University of Minnesota"
  
  out = c()
  for (i in 1:length(schoolnameV)) {
    out = c(out, pop[converter[[schoolnameV[i]]]][n[i],])
  }
  
  return(out)
}

thou_to_int = function(x) {
  y = str_replace_all(x, ',', '')
  y = str_replace_all(y, '-', '0')
  y = as.numeric(y)
  return(y)
}
#Loading Data
miac_id = c(174899, 174844, 174817, 174792, 175005, 173902, 173665, 173647, 173328, 174747, 173258, 173160, 173045)

enrollment = read.csv('/Users/blrosenberg/RStudio/DataViz/Hamline Finances/MNEnrollment.csv') %>%
  mutate_at(.vars=vars(-Unit.Id, -Institution.Name), .funs=thou_to_int)
en_miac = enrollment %>% filter(Unit.Id %in% miac_id) %>% select(-Unit.Id) %>% t() %>% data.frame()
rownames(en_miac) = str_replace_all(rownames(en_miac), 'X', '')
colnames(en_miac) = en_miac[1,]
en_miac = en_miac[2:11,]
pop = en_miac

id_name_conv = enrollment %>% filter(Unit.Id %in% miac_id) %>% select(Unit.Id, Institution.Name)

idnum_to_name = function(idnum) {
  return ((id_name_conv %>% filter(Unit.Id==idnum))$Institution.Name)
}

pc = read.csv('/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/990s/MIAC/PayCombined.csv') %>% 
  mutate(isHU = ifelse(School=="HU", "Hamline", "MIAC (mean)")) %>% mutate(pop = getPop(School, Year))

yrPop = pop %>% mutate(Year = rownames(pop)) %>%
  pivot_longer(cols=-c(Year), names_to="School", values_to="Population") %>% 
  mutate(School = str_replace_all(str_replace_all(School, '\\.s', "'s"), '\\.', ' '))
  
yrPop = yrPop %>% left_join(yrPop %>% group_by(Year) %>% summarize(MIAC_Pop = sum(as.numeric(Population)))) %>%
  mutate(Portion = as.numeric(Population)/MIAC_Pop)

courses = read.csv('/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/Bulletins/Workday/courses.csv')

programs = read.csv('/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/Bulletins/programs.csv') %>% mutate_at(.vars=c('cert', 'major', 'minor', 'prep', 'license', 'diploma'), .funs=as.logical) 
retention = read.csv('/Users/blrosenberg/RStudio/DataViz/Hamline Finances/Retention.csv')

for (i in 2012:2022) {
  assign(paste0('tuits', i), read.csv(paste0('/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/990s/Tuition/ic', i, '_ay.csv')))
}

tuits2012 = tuits2012 %>% mutate(UNITID = as.numeric(rownames(tuits2012)))
tuits_full = list(tuits2012, tuits2013, tuits2014, tuits2015,
             tuits2016, tuits2017, tuits2018, tuits2019,
             tuits2020, tuits2021, tuits2022) %>% reduce(full_join)
  
tuits2012 = tuits2012 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2012)
tuits2013 = tuits2013 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2013)
tuits2014 = tuits2014 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2014)
tuits2015 = tuits2015 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2015)
tuits2016 = tuits2016 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2016)
tuits2017 = tuits2017 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2017)
tuits2018 = tuits2018 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2018)
tuits2019 = tuits2019 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2019)
tuits2020 = tuits2020 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2020)
tuits2021 = tuits2021 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2021)
tuits2022 = tuits2022 %>% filter(UNITID %in% miac_id) %>% mutate(Name=idnum_to_name(UNITID), YR=2022)

tuits = list(tuits2012, tuits2013, tuits2014, tuits2015,
             tuits2016, tuits2017, tuits2018, tuits2019,
             tuits2020, tuits2021, tuits2022) %>% reduce(full_join)

tuits = tuits %>% mutate(amt = as.numeric(ifelse(TUITION1=="R", XTUIT1, TUITION1))) %>% select(Name, YR, amt) %>% mutate(isHU = ifelse(Name=="Hamline University", "Hamline", "MIAC"), Year=YR)
# Styling

font_add('Avenir', "/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/fonts/Avenir.ttc", bold="/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/fonts/AvenirBlack.ttf", italic="/Users/blrosenberg/Coding/Python_Projects/Classes/Oracle/fonts/AvenirLight.ttf")
textsz = 20

xscale = scale_x_continuous(breaks = c(2012:2021), limits=c(2012, 2021))
disc_size = scale_size_discrete(range=c(0.8, 2))
disc_col =scale_color_manual(values = c("#ea5545", "#f46a9b", "#ef9b20", "#edbf33", "#ede15b", "#bdcf32", "#87bc45", "#27aeef", "#b33dc6", "#00ffff", "#000000", "red", "darkgray", "blue"))
hides = guides(linetype="none", size="none")
dollars = scale_y_continuous(labels = scales::label_dollar())
pct = scale_y_continuous(labels = scales::label_percent())
btm = theme(legend.position="bottom")
miac_green = "#0f7754"
hamline_red = "#9d2235"

Introduction + Data Background

As part of my work for the campus newspaper, The Oracle, during President Miller’s retirement, I opted to review some of Hamline’s data to get a fuller, quantitative assessment of the state of the university throughout her eight-year presidency (Fall 2015 – Fall 2023).

The visualizations that follow make use of several queried sets of university population and tuition data from the National Center for Education Statistics’ Integrated Postsecondary Education Data System (IPEDS) in combination with my own custom-scraped datasets derived from a few different sources.

Namely, those are:

Students

Hamline is shrinking. Why it is shrinking is beyond our scope here, but these data do allow us to give more consideration to how severely and for how long the enrollment numbers have been falling. With that context, we are better prepared to assess Miller’s administration’s impact on enrollment. For better or worse, did they make a difference?

A decade ago, Hamline was one of the largest universities in its athletic conference, the Minnesota Intercollegiate Athletic Conference (MIAC). Since then, Hamline’s enrollment numbers have fallen.

Miller’s administration did not produce a noticeable change in the university’s depopulation rate.

Total Student Population over time, Hamline vs. mean in the MIAC

#pdf('PopulationChange.pdf', width=12, height=9)
en_miac %>% mutate(Year = rownames(en_miac)) %>%
  pivot_longer(cols=-c(Year), names_to="School", values_to="Population") %>% 
  mutate(isHU = ifelse(School=="Hamline University", "Hamline", "MIAC (mean)")) %>% 
  group_by(Year, isHU) %>% summarize(Population = mean(as.numeric(Population)), Year=as.numeric(Year[1])) %>%
  ggplot(aes(x=Year, y=Population)) + geom_line(aes(col=isHU), linewidth=4) + labs(col="", y="Total Student Population") +
  geom_vline(xintercept=2015.5, linetype="dashed") +
  geom_text(x=2015.7, y=4400, label="President Miller's First Term", angle=90, family="Avenir", face="italic", size=textsz*0.28) +
  scale_x_continuous(breaks=c(2012:2021), labels=c("'12", "'13", "'14", "'15", "'16", "'17", "'18", "'19", "'20", "'21")) + theme_minimal() +
  guides(col=guide_legend(nrow=2, byrow=T)) +
  theme(axis.text.x = element_text( vjust=1),
        text=element_text(family="Avenir", size=textsz),
        axis.title = element_text(face="bold", size=textsz*1.2),
        axis.title.x = element_text(hjust=0.5, vjust=-4),
        axis.title.y = element_text(hjust=0.5, vjust=1.4),
        plot.title = element_text(face="bold"),
        legend.position = "bottom",
        legend.direction = "vertical",
        legend.justification="right",
        legend.box.margin = margin(-50, 3, 0, 0),
        legend.text = element_text(size=textsz*0.95),
        legend.spacing.y = unit(20, "pt")
        ) + 
  scale_color_manual(values=c(hamline_red, miac_green))

#dev.off()

While Hamline’s enrollment fell steadily, enrollment numbers stayed relatively stable throughout the rest of the MIAC. As a result, the portion of students in the MIAC who attended Hamline also reliably decreased year after year.

The Shrinking Portion of MIAC Students Attending Hamline Since 2012

schoolCols = c("#666666", "#0069aa", "#0b5091", "#be0f34", "#E6B220", "#FFF", hamline_red, 
               "#D44420", "#000", "#E22739", "#4F2682", "#53585a", "#00447c")
schoolCols2 = c("#660033","#B09247","#FFD24F", "#000", "#003055","#FCCB06", "#888C8D", 
                "#01426A", "#FFFFFE", "#0C2F59", "#FFE153", "#242121", "#FFCB00")

aval <- list()
for(step in 1:10) {
  yr = step+2011
  aval[[step]] <-list(visible = FALSE,
                      name = paste0('Year = ', yr),
                      label = yr,
                      x=(yrPop %>% filter(Year==yr) %>% arrange(School))$School,
                      y=(yrPop %>% filter(Year==yr) %>% arrange(School))$Population,
                      text=(yrPop %>% filter(Year==yr) %>% arrange(School))$Portion)
}
aval[3][[1]]$visible = T

steps <- list()
fig <- plot_ly(sort=F)
for (i in 1:10) {
  yr = i+2011
  fig = fig %>% add_pie(labels=aval[i][[1]]$x, 
                        values=aval[i][[1]]$y,
                        #text=aval[i][[1]]$x,
                        visible = aval[i][[1]]$visible, 
                        marker = list(colors=schoolCols, line=list(color=schoolCols2, width=2)),
                        pull = 0.03,
                        name = '',#aval[i][[1]]$name, 
                        type = 'pie', 
                        hoverinfo = 'text',
                        hovertext = paste(
                          aval[i][[1]]$x, '\n', 
                          scales::percent(aval[i][[1]]$text, accuracy=0.01), 'of the MIAC\n', 
                          aval[i][[1]]$y, "Students"
                        ))

  step <- list(args = list('visible', rep(FALSE, length(aval))),
               method = 'restyle', label=yr)
  step$args[[2]][[i]] = TRUE  
  steps[[i]] = step 
} 

fig <- fig %>%
  layout(sliders = list(list(active = 0,
                             currentvalue = list(prefix = "Year: "),
                             steps = steps)))

fig

Like emigration from a country, the size of the student population at Hamline should be understood as complicated and affected subtly by many factors: some positive and some negative. Those factors include, but are not limited to, the number of applications, acceptance rate, enrollment rate (among those who have been admitted), transfers-in, transfers-out, and withdrawal rates. Put more simply: how many are coming in, how many are coming back, and how many are leaving?

Universities use a fairly strictly-defined metric, retention, to quantify the “How many are coming back?” portion of that equation. Rather than more generally tracking the portion of students in a given semester who also attended the same school in the previous semester, the National Center for Education Statistics specifically tracks the portion of a university’s first-time students in the fall semester of their first year (that year’s “cohort”) who return in subsequent semesters.3

Looking at Hamline’s officially reported retention rates since 2006, we can see a distinct change: long-term retention has fallen, and the size of the cohort has grown. Most notably, the cohort size grew by 35% from 2009 to 2012 while the four-year retention rate fell from 58% to 54.3% over that same period. Though that change precedes Miller’s term, the trend continued throughout the available data.

Change in Student Retention at Hamline, 2006-2019

p_to_n = function(period) {
  converter = list()
  converter["Fall1"] = 1
  converter["Fall2"] = 3
  converter["Fall3"] = 5
  converter["Fall4"] = 7
  converter["Spring1"] = 2
  converter["Spring2"] = 4
  converter["Spring3"] = 6
  converter["Spring4"] = 8
  out = c()
  for (i in period) {
    out = c(out, converter[[i]])
  }
  return(out)
}

ret2 = retention %>% mutate_all(.funs=as.numeric) %>% rename(Fall1N = Cohort) %>% 
  pivot_longer(cols=-c(Year), names_to="Period", values_to="Retained") %>% 
  mutate(isPct = !str_ends(Period, "N"), pct = Retained*isPct, Period = str_replace_all(Period, "N", ""), o=p_to_n(Period)) %>%
  group_by(Year, o) %>% summarize(pct=max(pct), ct=max(Retained))  %>% mutate(pct=ifelse(pct==0, 1, pct))

gg = ret2 %>% filter(Year==2006) %>%
  ggplot(aes(x=o, y=ct)) + geom_bar(aes(alpha=pct), stat="identity", fill=hamline_red) + coord_flip() +
  theme_minimal() + 
  scale_alpha_continuous(range=c(0.7, 1)) +
  scale_x_continuous(breaks=(1:8), 
                                       labels=c("1st Fall", "1st Spring",
                                                "2nd Fall", "2nd Spring",
                                                "3rd Fall", "3rd Spring",
                                                "4th Fall", "4th Spring")) + 
  labs(y="Full-Time Students Retained", x="Semesters at Hamline", title="Rention at Hamline") + 
  theme(plot.title=element_text(hjust=0.5)) + guides(alpha="none")

aval <- list()
for(step in 1:14) {
  yr = step+2005
  aval[[step]] <-list(visible = FALSE,
                      name = paste0('Year = ', yr),
                      label = yr,
                      pd=c("1st Fall Semester", "1st Spring Semester",
                            "2nd Fall Semester", "2nd Spring Semester",
                            "3rd Fall Semester", "3rd Spring Semester",
                            "4th Fall Semester", "4th Spring Semester"),
                      x=1:8,
                      y=(ret2 %>% filter(Year==yr))$ct,
                      alpha=(ret2 %>% filter(Year==yr))$pct)
}
aval[1][[1]]$visible = T

steps <- list()
fig <- plot_ly()
for (i in 1:14) {
  yr = i+2005
  fig = fig %>% add_bars(y=aval[i][[1]]$pd, x=aval[i][[1]]$y, 
                         text=scales::percent(aval[i][[1]]$alpha),
                         #opacity = aval[i][[1]]$alpha, 
                         marker = list(color=hamline_red, opacity = aval[i][[1]]$alpha/2+0.5),
                         visible = aval[i][[1]]$visible, 
                         name = '', 
                         type = 'bar', 
                         hoverinfo = 'text',
                         hovertext = paste(aval[i][[1]]$y, "students"),
                         orientation= 'h', showlegend=F)

  step <- list(args = list('visible', rep(FALSE, length(aval))),
               method = 'restyle', label=yr)
  step$args[[2]][[i]] = TRUE  
  steps[[i]] = step 
} 


fig = fig %>%
  layout(sliders = list(list(active = 0,
                             currentvalue = list(prefix = "Year: "),
                             steps = steps,
                             pad = list(t=60))),
                    xaxis = list(title="Full-Time Students Retained from First-Year Cohort", range=c(0, 600)),
         margin = list(pad=10)
) 

fig

Academic Programs

Anecdotally, my conversations with Hamline professors about Miller’s administration have tended toward airing out frustrations with several years of “rightsizing” and “program review” which aimed to reduce expenses by removing or restricting academic programs with limited attendance or limited financial returns. While their complaints are often qualitative—including a sense of job insecurity and interdepartmental tension over their shared, scant resources—we will proceed with one coarse approach for quantifying this upheaval.

I gathered data from the University’s bulletins to tabulate the Academic Programs offered for each of the past 14 years. By comparing each year to the previous year, we can see how many programs were added and how many were removed.

There are important limits to these data which should be considered: the comparison between years relies entirely on the literal names of the programs offered. If a “Bachelor of Arts in Public Health” is relabeled as a “Bachelor of Arts (BA) in Public Health” the next year, that is counted as both 1 program lost and 1 program gained. Still, an imbalance of program changes signifies a true loss or gain of a program, and many name changes do reflect a real, substantive change to the program.

Since Miller’s term began, we can see a clear, new trend of growing upheaval in the programs offered at Hamline.

Yearly change in the number of academic programs at Hamline since 2009

programs %>% select(-c(cert, major, minor, prep, license, diploma)) %>% 
  left_join(programs %>% group_by(name) %>% summarize(s = min(yr), e=max(yr))) %>% 
  group_by(name) %>% summarize(Started=s[1], Ended=e[1]) %>%
  mutate(fm=Started>2014) %>%
  pivot_longer(cols=c(Started, Ended), names_to = "type", values_to = "dt") %>%
  filter(dt > 2008, dt<2023) %>%
  group_by(dt, type) %>% summarize(amt=length(dt)) %>%
  mutate(amt = ifelse(type=="Ended", -amt, amt), 
         type = factor(type, levels=c("Started", "Ended"), labels=c("Programs Started", "Programs Ended"))) %>%
  ggplot(aes(x=dt, y=amt, fill=type)) + geom_bar(stat='identity') + 
  geom_vline(xintercept=2015.5, linetype="dashed") +
  geom_text(x=2015.7, y=-38, label="President Miller's First Term", angle=90, family="Avenir", face="italic", size=textsz*0.28) +
  scale_x_continuous(breaks=c(2009:2022), labels=c("'09", "'10", "'11", "'12", "'13", "'14", "'15", "'16", "'17", "'18", "'19", "'20", "'21", "'22")) +
  labs(x="Year", y="Change in the number of academic programs", fill="") + theme_minimal() + 
  guides(fill=guide_legend(nrow=2, byrow=T)) +
  theme(axis.text.x = element_text( vjust=1),
        text=element_text(family="Avenir", size=textsz),
        axis.title = element_text(face="bold", size=textsz*1.2),
        axis.title.x = element_text(hjust=0.5, vjust=-4),
        axis.title.y = element_text(hjust=1.5, vjust=1.4),
        plot.title = element_text(face="bold"),
        legend.position = "bottom",
        legend.direction = "vertical",
        legend.justification="right",
        legend.box.margin = margin(-50, 3, 0, 0),
        legend.text = element_text(size=textsz*0.95),
        legend.spacing.y = unit(20, "pt")
        ) + 
  scale_fill_manual(values=c("darkgray", hamline_red))

Finances

Lastly, I explored Hamline’s finances since 2012.

Despite the reliable frustration in response to Hamline’s annual tuition increase announcement, nearly every university raises its tuition year after year. Still, the university’s financial stability has been a major concern since before Miller’s presidency, and with a sizable budget deficit looming over campus, this Miller’s final year looks no different.

When I interviewed President Miller on Nov. 30, 2023, she confirmed that the annual tuition change is part of Hamline being a “tuition-funded University” affected by inflation and declining enrollment and that she had prioritized growing the school’s endowment throughout her term.

The financial reports of private, non-profit universities like Hamline are public4. This form includes an itemized list of major expenses which are totaled into a single “Total Expenses” field. When that number is divided by the university’s reported enrollment, we arrive at an approximated Expenses Per Student which might reasonably be expected to correlate with what the university charges for tuition. In the MIAC at large, it does. At Hamline, despite declining enrollment numbers, the reported Expenses Per Student fell from more than $40k to less than $25k while tuition steadily climbed past $40k. Where is all that money going?

Reported Expenses Per Student vs Tuition

p1 = pc %>% select(School, TotalExpenses, Year) %>% 
  group_by(School, Year) %>% filter(Year < 2021) %>% summarize(School=School[1], Year=Year[1], TotalExpenses=TotalExpenses[1]) %>% 
  mutate(Pop = as.numeric(getPop(School, Year)), 
         ExpensePerStudent=TotalExpenses/Pop, 
         isHU = ifelse(School=="HU", "Hamline", "MIAC")) %>% 
  group_by(isHU, Year) %>% summarize(ExpensePerStudent = mean(ExpensePerStudent)) %>% left_join(tuits %>% filter(isHU=="Hamline")) %>%
  filter(isHU=="Hamline") %>%
  ggplot(aes(x=Year, y=ExpensePerStudent)) + scale_x_continuous(breaks=2012:2020) +
  geom_area(aes(y=amt), linetype="dashed", linewidth=4, fill="#9d2235") + 
  theme_minimal() + 
  geom_area(linewidth=4, fill="darkgray", alpha=0.8) +
  scale_y_continuous(labels = scales::label_dollar(), limits=c(0, 50000)) +
  geom_text(x=2016, y=10000, label="Total university expenses per student", family="Avenir", size=textsz*0.25) +
  geom_text(x=2018, y=35000, label="Hamline university in-state tuition", col="white", family="Avenir", size=textsz*0.25) + 
  labs(y="Cost of tuition and cost of university expenses (USD)\n", x="\nYear", title="Tuition vs. university expenses per student at Hamline University") + 
  theme(plot.title = element_text(hjust=0.5, face="bold"),
        axis.title = element_text(face="bold"),
        text = element_text(family="Avenir", size=textsz*0.6))

p2 = pc %>% select(School, TotalExpenses, Year) %>% 
  group_by(School, Year) %>% filter(Year < 2021) %>% summarize(School=School[1], Year=Year[1], TotalExpenses=TotalExpenses[1]) %>% 
  mutate(Pop = as.numeric(getPop(School, Year)), 
         ExpensePerStudent=TotalExpenses/Pop, 
         isHU = ifelse(School=="HU", "Hamline", "MIAC")) %>% 
  group_by(isHU, Year) %>% summarize(ExpensePerStudent = mean(ExpensePerStudent)) %>% left_join(tuits %>% mutate(isHU!="Hamline")) %>%
  group_by(isHU, Year) %>% summarize(ExpensePerStudent = mean(ExpensePerStudent), amt=mean(amt)) %>%
  filter(isHU!="Hamline") %>%
  ggplot(aes(x=Year, y=ExpensePerStudent)) + scale_x_continuous(breaks=2012:2020) +
  theme_minimal() + 
  geom_area(linewidth=4, fill="darkgray", alpha=0.8) +
  geom_area(aes(y=amt), linetype="dashed", linewidth=4, fill="#0f7754") + 
  scale_y_continuous(labels = scales::label_dollar(), limits=c(0, 50000)) +
  geom_text(x=2014.6, y=41000, label="Mean total university expenses per student", family="Avenir", size=textsz*0.25) +
  geom_text(x=2016, y=20000, label="MIAC mean in-state tuition", col="white", family="Avenir", size=textsz*0.25) + 
  labs(y="Cost of tuition and cost of university expenses (USD)\n", x="\nYear", title="Tuition vs. university expenses per student in the MIAC") + 
  theme(plot.title = element_text(hjust=0.5, face="bold"),
        axis.title = element_text(face="bold"),
        text = element_text(family="Avenir", size=textsz*0.6))


grid.arrange(p1, p2, ncol=2)

The MIAC schools vary significantly, and that in turn limits the meaning of any direct comparison of the dollar amount of administrative salaries at different schools. However, Form 990 also includes a report of all compensation paid to university employees. By instead comparing the portion of all university compensation that is paid to the university president, we can see that Hamline’s presidential portion has grown sizably since the start of Miller’s presidency, not only in excess of the MIAC average but in complete opposition to the average decrease seen during the COVID-19 pandemic.

Change in the Presidential Portion of All Compensation, Hamline vs. Mean in the MIAC

#pdf('PresPayChange.pdf', width=12, height=9)

pc %>% filter(Title %in% c("PRESIDENT", "President"), !(School %in% c("St. Mary", "St. Kate"))) %>% 
  mutate(CompRate = ReportableCompFromOrg/(OfficerPay + OtherSalaries)) %>% 
  group_by(isHU, Year) %>% summarize(CompRate = mean(CompRate)) %>% arrange(Year) %>%
  ggplot(aes(x=Year, y=CompRate)) + geom_line(aes(color=isHU), linewidth=5) + pct +
  theme_minimal() + labs(col="", y = "Presidential portion of all university compensation") +
  geom_vline(xintercept=2015, linetype="dashed") +
  geom_text(aes(x=-900), x=2015.2, y=0.015, label="President Miller's First Term", angle=90, family="Avenir",
            size=textsz*0.28) +
  scale_x_continuous(breaks=c(2012:2021), 
                     labels=c("'12", "'13", "'14", "'15", "'16", "'17", "'18", "'19", "'20", "'21"), 
                     limits=c(2012, 2021)) +
  guides(col=guide_legend(nrow=2, byrow=T), label = F, text = F, col=F) +
  theme(axis.text.x = element_text( vjust=1),
        text=element_text(family="Avenir", size=textsz),
        axis.title = element_text(face="bold", size=textsz*1.2),
        axis.title.x = element_text(hjust=0.5, vjust=-4),
        axis.title.y = element_text(hjust=1, vjust=1.4),
        plot.title = element_text(face="bold"),
        legend.position = "bottom",
        legend.direction = "vertical",
        legend.justification="right",
        legend.box.margin = margin(-50, 3, 0, 0),
        legend.text = element_text(size=textsz*0.95),
        legend.spacing.y = unit(20, "pt")
        ) + 
  scale_color_manual(values=c(hamline_red, miac_green))

#dev.off()

Notes


  1. I used Python to manually wrangle some of the XML into a dataframe saved as a CSV.↩︎

  2. I used the Python package BeautifulSoup to scrape previous years’ course listing pages↩︎

  3. Wherever an individual retention figure is reported for a university, it generally refers to the portion of the previous year’s cohort who returned for the fall semester of their second year.↩︎

  4. Though there is often a lengthy (multi-year) delay between a year’s tax season and public access to the 990 form.↩︎

LS0tCnRpdGxlOiAiVGhlIFN0YXRlIG9mIEhhbWxpbmUgVW5pdmVyc2l0eSIKYXV0aG9yOiAiQmVuIFJvc2VuYmVyZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIG9wZW5pbnRybzo6bGFiX3JlcG9ydDoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IGpvdXJuYWwKCi0tLQoKYGBge3IgbG9hZC1wYWNrYWdlcywgbWVzc2FnZT1GQUxTRSwgZWNobz1GLCByZXN1bHRzPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShzaG93dGV4dCkKbGlicmFyeShzaGlueSkKbGlicmFyeShwdXJycikKbGlicmFyeShncmlkRXh0cmEpCgpzaG93dGV4dF9hdXRvKCkKCgoja25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGLCB3YXJuaW5nPUYsIG1lc3NhZ2U9RiwgZmlnLndpZHRoPTgpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVCwgd2FybmluZz1GLCBtZXNzYWdlPUYsIGZpZy53aWR0aD04KQoKcm0obGlzdCA9IGxzKCkpCmBgYAoKYGBge3J9CiMgQ3VzdG9tIEZ1bmN0aW9ucwoKZ2V0UG9wID0gZnVuY3Rpb24oc2Nob29sbmFtZVYsIHllYXJWKSB7CiAgbiA9IHllYXJWLTIwMTEKICBjb252ZXJ0ZXIgPSBsaXN0KCkKICBjb252ZXJ0ZXJbWyJNYWNhbGVzdGVyIl1dID0gIk1hY2FsZXN0ZXIgQ29sbGVnZSIKICBjb252ZXJ0ZXJbWyJIVSJdXSA9ICAiSGFtbGluZSBVbml2ZXJzaXR5IgogIGNvbnZlcnRlcltbIlN0LiBPbGFmIl1dID0gIlN0IE9sYWYgQ29sbGVnZSIKICBjb252ZXJ0ZXJbWyJHdXN0YXZ1cyJdXSA9ICAiR3VzdGF2dXMgQWRvbHBodXMgQ29sbGVnZSIKICBjb252ZXJ0ZXJbWyJCZXRoZWwiXV0gPSAiQmV0aGVsIFVuaXZlcnNpdHkiCiAgY29udmVydGVyW1siQXVnc2J1cmciXV0gPSAgIkF1Z3NidXJnIFVuaXZlcnNpdHkiCiAgY29udmVydGVyW1siQ2FybGV0b24iXV0gPSAgIkNhcmxldG9uIENvbGxlZ2UiCiAgY29udmVydGVyW1siU3QuIEJlbmVkaWN0Il1dID0gIkNvbGxlZ2Ugb2YgU2FpbnQgQmVuZWRpY3QiCiAgY29udmVydGVyW1siQ29uY29yZGlhIl1dID0gIkNvbmNvcmRpYSBVbml2ZXJzaXR5LVNhaW50IFBhdWwiCiAgY29udmVydGVyW1siU3QuIEpvaG4iXV0gPSAiU2FpbnQgSm9obnMgVW5pdmVyc2l0eSIKICBjb252ZXJ0ZXJbWyJTdC4gU2Nob2xhc3RpY2EiXV0gPSAiVGhlIENvbGxlZ2Ugb2YgU2FpbnQgU2Nob2xhc3RpY2EiCiAgY29udmVydGVyW1siU3QuIEthdGUiXV0gPSJTdCBDYXRoZXJpbmUgVW5pdmVyc2l0eSIKICBjb252ZXJ0ZXJbWyJTdC4gTWFyeSJdXSA9IlNhaW50IE1hcnkncyBVbml2ZXJzaXR5IG9mIE1pbm5lc290YSIKICAKICBvdXQgPSBjKCkKICBmb3IgKGkgaW4gMTpsZW5ndGgoc2Nob29sbmFtZVYpKSB7CiAgICBvdXQgPSBjKG91dCwgcG9wW2NvbnZlcnRlcltbc2Nob29sbmFtZVZbaV1dXV1bbltpXSxdKQogIH0KICAKICByZXR1cm4ob3V0KQp9Cgp0aG91X3RvX2ludCA9IGZ1bmN0aW9uKHgpIHsKICB5ID0gc3RyX3JlcGxhY2VfYWxsKHgsICcsJywgJycpCiAgeSA9IHN0cl9yZXBsYWNlX2FsbCh5LCAnLScsICcwJykKICB5ID0gYXMubnVtZXJpYyh5KQogIHJldHVybih5KQp9CgpgYGAKCmBgYHtyIG1lc3NhZ2U9Rn0KI0xvYWRpbmcgRGF0YQptaWFjX2lkID0gYygxNzQ4OTksIDE3NDg0NCwgMTc0ODE3LCAxNzQ3OTIsIDE3NTAwNSwgMTczOTAyLCAxNzM2NjUsIDE3MzY0NywgMTczMzI4LCAxNzQ3NDcsIDE3MzI1OCwgMTczMTYwLCAxNzMwNDUpCgplbnJvbGxtZW50ID0gcmVhZC5jc3YoJy9Vc2Vycy9ibHJvc2VuYmVyZy9SU3R1ZGlvL0RhdGFWaXovSGFtbGluZSBGaW5hbmNlcy9NTkVucm9sbG1lbnQuY3N2JykgJT4lCiAgbXV0YXRlX2F0KC52YXJzPXZhcnMoLVVuaXQuSWQsIC1JbnN0aXR1dGlvbi5OYW1lKSwgLmZ1bnM9dGhvdV90b19pbnQpCmVuX21pYWMgPSBlbnJvbGxtZW50ICU+JSBmaWx0ZXIoVW5pdC5JZCAlaW4lIG1pYWNfaWQpICU+JSBzZWxlY3QoLVVuaXQuSWQpICU+JSB0KCkgJT4lIGRhdGEuZnJhbWUoKQpyb3duYW1lcyhlbl9taWFjKSA9IHN0cl9yZXBsYWNlX2FsbChyb3duYW1lcyhlbl9taWFjKSwgJ1gnLCAnJykKY29sbmFtZXMoZW5fbWlhYykgPSBlbl9taWFjWzEsXQplbl9taWFjID0gZW5fbWlhY1syOjExLF0KcG9wID0gZW5fbWlhYwoKaWRfbmFtZV9jb252ID0gZW5yb2xsbWVudCAlPiUgZmlsdGVyKFVuaXQuSWQgJWluJSBtaWFjX2lkKSAlPiUgc2VsZWN0KFVuaXQuSWQsIEluc3RpdHV0aW9uLk5hbWUpCgppZG51bV90b19uYW1lID0gZnVuY3Rpb24oaWRudW0pIHsKICByZXR1cm4gKChpZF9uYW1lX2NvbnYgJT4lIGZpbHRlcihVbml0LklkPT1pZG51bSkpJEluc3RpdHV0aW9uLk5hbWUpCn0KCnBjID0gcmVhZC5jc3YoJy9Vc2Vycy9ibHJvc2VuYmVyZy9Db2RpbmcvUHl0aG9uX1Byb2plY3RzL0NsYXNzZXMvT3JhY2xlLzk5MHMvTUlBQy9QYXlDb21iaW5lZC5jc3YnKSAlPiUgCiAgbXV0YXRlKGlzSFUgPSBpZmVsc2UoU2Nob29sPT0iSFUiLCAiSGFtbGluZSIsICJNSUFDIChtZWFuKSIpKSAlPiUgbXV0YXRlKHBvcCA9IGdldFBvcChTY2hvb2wsIFllYXIpKQoKeXJQb3AgPSBwb3AgJT4lIG11dGF0ZShZZWFyID0gcm93bmFtZXMocG9wKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHM9LWMoWWVhciksIG5hbWVzX3RvPSJTY2hvb2wiLCB2YWx1ZXNfdG89IlBvcHVsYXRpb24iKSAlPiUgCiAgbXV0YXRlKFNjaG9vbCA9IHN0cl9yZXBsYWNlX2FsbChzdHJfcmVwbGFjZV9hbGwoU2Nob29sLCAnXFwucycsICIncyIpLCAnXFwuJywgJyAnKSkKICAKeXJQb3AgPSB5clBvcCAlPiUgbGVmdF9qb2luKHlyUG9wICU+JSBncm91cF9ieShZZWFyKSAlPiUgc3VtbWFyaXplKE1JQUNfUG9wID0gc3VtKGFzLm51bWVyaWMoUG9wdWxhdGlvbikpKSkgJT4lCiAgbXV0YXRlKFBvcnRpb24gPSBhcy5udW1lcmljKFBvcHVsYXRpb24pL01JQUNfUG9wKQoKY291cnNlcyA9IHJlYWQuY3N2KCcvVXNlcnMvYmxyb3NlbmJlcmcvQ29kaW5nL1B5dGhvbl9Qcm9qZWN0cy9DbGFzc2VzL09yYWNsZS9CdWxsZXRpbnMvV29ya2RheS9jb3Vyc2VzLmNzdicpCgpwcm9ncmFtcyA9IHJlYWQuY3N2KCcvVXNlcnMvYmxyb3NlbmJlcmcvQ29kaW5nL1B5dGhvbl9Qcm9qZWN0cy9DbGFzc2VzL09yYWNsZS9CdWxsZXRpbnMvcHJvZ3JhbXMuY3N2JykgJT4lIG11dGF0ZV9hdCgudmFycz1jKCdjZXJ0JywgJ21ham9yJywgJ21pbm9yJywgJ3ByZXAnLCAnbGljZW5zZScsICdkaXBsb21hJyksIC5mdW5zPWFzLmxvZ2ljYWwpIApyZXRlbnRpb24gPSByZWFkLmNzdignL1VzZXJzL2Jscm9zZW5iZXJnL1JTdHVkaW8vRGF0YVZpei9IYW1saW5lIEZpbmFuY2VzL1JldGVudGlvbi5jc3YnKQoKZm9yIChpIGluIDIwMTI6MjAyMikgewogIGFzc2lnbihwYXN0ZTAoJ3R1aXRzJywgaSksIHJlYWQuY3N2KHBhc3RlMCgnL1VzZXJzL2Jscm9zZW5iZXJnL0NvZGluZy9QeXRob25fUHJvamVjdHMvQ2xhc3Nlcy9PcmFjbGUvOTkwcy9UdWl0aW9uL2ljJywgaSwgJ19heS5jc3YnKSkpCn0KCnR1aXRzMjAxMiA9IHR1aXRzMjAxMiAlPiUgbXV0YXRlKFVOSVRJRCA9IGFzLm51bWVyaWMocm93bmFtZXModHVpdHMyMDEyKSkpCnR1aXRzX2Z1bGwgPSBsaXN0KHR1aXRzMjAxMiwgdHVpdHMyMDEzLCB0dWl0czIwMTQsIHR1aXRzMjAxNSwKICAgICAgICAgICAgIHR1aXRzMjAxNiwgdHVpdHMyMDE3LCB0dWl0czIwMTgsIHR1aXRzMjAxOSwKICAgICAgICAgICAgIHR1aXRzMjAyMCwgdHVpdHMyMDIxLCB0dWl0czIwMjIpICU+JSByZWR1Y2UoZnVsbF9qb2luKQogIAp0dWl0czIwMTIgPSB0dWl0czIwMTIgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDEyKQp0dWl0czIwMTMgPSB0dWl0czIwMTMgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDEzKQp0dWl0czIwMTQgPSB0dWl0czIwMTQgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDE0KQp0dWl0czIwMTUgPSB0dWl0czIwMTUgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDE1KQp0dWl0czIwMTYgPSB0dWl0czIwMTYgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDE2KQp0dWl0czIwMTcgPSB0dWl0czIwMTcgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDE3KQp0dWl0czIwMTggPSB0dWl0czIwMTggJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDE4KQp0dWl0czIwMTkgPSB0dWl0czIwMTkgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDE5KQp0dWl0czIwMjAgPSB0dWl0czIwMjAgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDIwKQp0dWl0czIwMjEgPSB0dWl0czIwMjEgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDIxKQp0dWl0czIwMjIgPSB0dWl0czIwMjIgJT4lIGZpbHRlcihVTklUSUQgJWluJSBtaWFjX2lkKSAlPiUgbXV0YXRlKE5hbWU9aWRudW1fdG9fbmFtZShVTklUSUQpLCBZUj0yMDIyKQoKdHVpdHMgPSBsaXN0KHR1aXRzMjAxMiwgdHVpdHMyMDEzLCB0dWl0czIwMTQsIHR1aXRzMjAxNSwKICAgICAgICAgICAgIHR1aXRzMjAxNiwgdHVpdHMyMDE3LCB0dWl0czIwMTgsIHR1aXRzMjAxOSwKICAgICAgICAgICAgIHR1aXRzMjAyMCwgdHVpdHMyMDIxLCB0dWl0czIwMjIpICU+JSByZWR1Y2UoZnVsbF9qb2luKQoKdHVpdHMgPSB0dWl0cyAlPiUgbXV0YXRlKGFtdCA9IGFzLm51bWVyaWMoaWZlbHNlKFRVSVRJT04xPT0iUiIsIFhUVUlUMSwgVFVJVElPTjEpKSkgJT4lIHNlbGVjdChOYW1lLCBZUiwgYW10KSAlPiUgbXV0YXRlKGlzSFUgPSBpZmVsc2UoTmFtZT09IkhhbWxpbmUgVW5pdmVyc2l0eSIsICJIYW1saW5lIiwgIk1JQUMiKSwgWWVhcj1ZUikKYGBgCgpgYGB7ciB3YXJuaW5nPUZ9CiMgU3R5bGluZwoKZm9udF9hZGQoJ0F2ZW5pcicsICIvVXNlcnMvYmxyb3NlbmJlcmcvQ29kaW5nL1B5dGhvbl9Qcm9qZWN0cy9DbGFzc2VzL09yYWNsZS9mb250cy9BdmVuaXIudHRjIiwgYm9sZD0iL1VzZXJzL2Jscm9zZW5iZXJnL0NvZGluZy9QeXRob25fUHJvamVjdHMvQ2xhc3Nlcy9PcmFjbGUvZm9udHMvQXZlbmlyQmxhY2sudHRmIiwgaXRhbGljPSIvVXNlcnMvYmxyb3NlbmJlcmcvQ29kaW5nL1B5dGhvbl9Qcm9qZWN0cy9DbGFzc2VzL09yYWNsZS9mb250cy9BdmVuaXJMaWdodC50dGYiKQp0ZXh0c3ogPSAyMAoKeHNjYWxlID0gc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMjAxMjoyMDIxKSwgbGltaXRzPWMoMjAxMiwgMjAyMSkpCmRpc2Nfc2l6ZSA9IHNjYWxlX3NpemVfZGlzY3JldGUocmFuZ2U9YygwLjgsIDIpKQpkaXNjX2NvbCA9c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNlYTU1NDUiLCAiI2Y0NmE5YiIsICIjZWY5YjIwIiwgIiNlZGJmMzMiLCAiI2VkZTE1YiIsICIjYmRjZjMyIiwgIiM4N2JjNDUiLCAiIzI3YWVlZiIsICIjYjMzZGM2IiwgIiMwMGZmZmYiLCAiIzAwMDAwMCIsICJyZWQiLCAiZGFya2dyYXkiLCAiYmx1ZSIpKQpoaWRlcyA9IGd1aWRlcyhsaW5ldHlwZT0ibm9uZSIsIHNpemU9Im5vbmUiKQpkb2xsYXJzID0gc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bGFiZWxfZG9sbGFyKCkpCnBjdCA9IHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSkKYnRtID0gdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQptaWFjX2dyZWVuID0gIiMwZjc3NTQiCmhhbWxpbmVfcmVkID0gIiM5ZDIyMzUiCmBgYAoKIyBJbnRyb2R1Y3Rpb24gKyBEYXRhIEJhY2tncm91bmQKCkFzIHBhcnQgb2YgbXkgd29yayBmb3IgdGhlIGNhbXB1cyBuZXdzcGFwZXIsICpUaGUgT3JhY2xlKiwgZHVyaW5nIFByZXNpZGVudCBNaWxsZXIncyByZXRpcmVtZW50LCBJIG9wdGVkIHRvIHJldmlldyBzb21lIG9mIEhhbWxpbmUncyBkYXRhIHRvIGdldCBhIGZ1bGxlciwgcXVhbnRpdGF0aXZlIGFzc2Vzc21lbnQgb2YgdGhlIHN0YXRlIG9mIHRoZSB1bml2ZXJzaXR5IHRocm91Z2hvdXQgaGVyIGVpZ2h0LXllYXIgcHJlc2lkZW5jeSAoRmFsbCAyMDE1IC0tIEZhbGwgMjAyMykuCgpUaGUgdmlzdWFsaXphdGlvbnMgdGhhdCBmb2xsb3cgbWFrZSB1c2Ugb2Ygc2V2ZXJhbCBxdWVyaWVkIHNldHMgb2YgW3VuaXZlcnNpdHkgcG9wdWxhdGlvbiBhbmQgdHVpdGlvbiBkYXRhIGZyb20gdGhlIE5hdGlvbmFsIENlbnRlciBmb3IgRWR1Y2F0aW9uIFN0YXRpc3RpY3MnIEludGVncmF0ZWQgUG9zdHNlY29uZGFyeSBFZHVjYXRpb24gRGF0YSBTeXN0ZW0gKElQRURTKV0oaHR0cHM6Ly9uY2VzLmVkLmdvdi9pcGVkcy9kYXRhY2VudGVyL0luc3RpdHV0aW9uTGlzdC5hc3B4P3N0ZXBJZD0xJnZpZXdpbnN0aXR1dGlvbnM9dmlldyZzaWQ9YzZhODkwOTUtOWExNS00NGU5LTkzNjktZDllYzVkYzBiZjczJnJ0aWQ9MSkgaW4gY29tYmluYXRpb24gd2l0aCBteSBvd24gY3VzdG9tLXNjcmFwZWQgZGF0YXNldHMgZGVyaXZlZCBmcm9tIGEgZmV3IGRpZmZlcmVudCBzb3VyY2VzLgoKTmFtZWx5LCB0aG9zZSBhcmU6CgoqIFhNTCBmb3JtYXR0ZWQgWzk5MCBmb3JtcyBwcm92aWRlZCBieSBQcm9QdWJsaWNhXShodHRwczovL3Byb2plY3RzLnByb3B1YmxpY2Eub3JnL25vbnByb2ZpdHMvb3JnYW5pemF0aW9ucy80MTA2OTM5NjApIF5bSSB1c2VkIFB5dGhvbiB0byBtYW51YWxseSB3cmFuZ2xlIHNvbWUgb2YgdGhlIFhNTCBpbnRvIGEgZGF0YWZyYW1lIHNhdmVkIGFzIGEgQ1NWLl0KKiBIYW1saW5lJ3MgcmVnaXN0cmF0aW9uIHBsYXRmb3JtLCBXb3JrZGF5LiBeW0kgdXNlZCB0aGUgUHl0aG9uIHBhY2thZ2UgQmVhdXRpZnVsU291cCB0byBzY3JhcGUgcHJldmlvdXMgeWVhcnMnIGNvdXJzZSBsaXN0aW5nIHBhZ2VzXQoqIFtIYW1saW5lJ3MgcHJldmlvdXNseSBwb3N0ZWQgYnVsbGV0aW5zXShodHRwOi8vYnVsbGV0aW4uaGFtbGluZS5lZHUvY29udGVudC5waHA/Y2F0b2lkPTMyJm5hdm9pZD0xNTY0KQoKIyBTdHVkZW50cwoKSGFtbGluZSBpcyBzaHJpbmtpbmcuICpXaHkqIGl0IGlzIHNocmlua2luZyBpcyBiZXlvbmQgb3VyIHNjb3BlIGhlcmUsIGJ1dCB0aGVzZSBkYXRhIGRvIGFsbG93IHVzIHRvIGdpdmUgbW9yZSBjb25zaWRlcmF0aW9uIHRvICpob3cgc2V2ZXJlbHkqIGFuZCAqZm9yIGhvdyBsb25nKiB0aGUgZW5yb2xsbWVudCBudW1iZXJzIGhhdmUgYmVlbiBmYWxsaW5nLiBXaXRoIHRoYXQgY29udGV4dCwgd2UgYXJlIGJldHRlciBwcmVwYXJlZCB0byBhc3Nlc3MgTWlsbGVyJ3MgYWRtaW5pc3RyYXRpb24ncyBpbXBhY3Qgb24gZW5yb2xsbWVudC4gRm9yIGJldHRlciBvciB3b3JzZSwgZGlkIHRoZXkgbWFrZSBhIGRpZmZlcmVuY2U/IAoKQSBkZWNhZGUgYWdvLCBIYW1saW5lIHdhcyBvbmUgb2YgdGhlIGxhcmdlc3QgdW5pdmVyc2l0aWVzIGluIGl0cyBhdGhsZXRpYyBjb25mZXJlbmNlLCB0aGUgTWlubmVzb3RhIEludGVyY29sbGVnaWF0ZSBBdGhsZXRpYyBDb25mZXJlbmNlIChNSUFDKS4gU2luY2UgdGhlbiwgSGFtbGluZSdzIGVucm9sbG1lbnQgbnVtYmVycyBoYXZlIGZhbGxlbi4gCgpNaWxsZXIncyBhZG1pbmlzdHJhdGlvbiBkaWQgbm90IHByb2R1Y2UgYSBub3RpY2VhYmxlIGNoYW5nZSBpbiB0aGUgdW5pdmVyc2l0eSdzIGRlcG9wdWxhdGlvbiByYXRlLgoKIyMgVG90YWwgU3R1ZGVudCBQb3B1bGF0aW9uIG92ZXIgdGltZSwgSGFtbGluZSB2cy4gbWVhbiBpbiB0aGUgTUlBQwoKCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD05LCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KI3BkZignUG9wdWxhdGlvbkNoYW5nZS5wZGYnLCB3aWR0aD0xMiwgaGVpZ2h0PTkpCmVuX21pYWMgJT4lIG11dGF0ZShZZWFyID0gcm93bmFtZXMoZW5fbWlhYykpICU+JQogIHBpdm90X2xvbmdlcihjb2xzPS1jKFllYXIpLCBuYW1lc190bz0iU2Nob29sIiwgdmFsdWVzX3RvPSJQb3B1bGF0aW9uIikgJT4lIAogIG11dGF0ZShpc0hVID0gaWZlbHNlKFNjaG9vbD09IkhhbWxpbmUgVW5pdmVyc2l0eSIsICJIYW1saW5lIiwgIk1JQUMgKG1lYW4pIikpICU+JSAKICBncm91cF9ieShZZWFyLCBpc0hVKSAlPiUgc3VtbWFyaXplKFBvcHVsYXRpb24gPSBtZWFuKGFzLm51bWVyaWMoUG9wdWxhdGlvbikpLCBZZWFyPWFzLm51bWVyaWMoWWVhclsxXSkpICU+JQogIGdncGxvdChhZXMoeD1ZZWFyLCB5PVBvcHVsYXRpb24pKSArIGdlb21fbGluZShhZXMoY29sPWlzSFUpLCBsaW5ld2lkdGg9NCkgKyBsYWJzKGNvbD0iIiwgeT0iVG90YWwgU3R1ZGVudCBQb3B1bGF0aW9uIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0yMDE1LjUsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgZ2VvbV90ZXh0KHg9MjAxNS43LCB5PTQ0MDAsIGxhYmVsPSJQcmVzaWRlbnQgTWlsbGVyJ3MgRmlyc3QgVGVybSIsIGFuZ2xlPTkwLCBmYW1pbHk9IkF2ZW5pciIsIGZhY2U9Iml0YWxpYyIsIHNpemU9dGV4dHN6KjAuMjgpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMjAxMjoyMDIxKSwgbGFiZWxzPWMoIicxMiIsICInMTMiLCAiJzE0IiwgIicxNSIsICInMTYiLCAiJzE3IiwgIicxOCIsICInMTkiLCAiJzIwIiwgIicyMSIpKSArIHRoZW1lX21pbmltYWwoKSArCiAgZ3VpZGVzKGNvbD1ndWlkZV9sZWdlbmQobnJvdz0yLCBieXJvdz1UKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KCB2anVzdD0xKSwKICAgICAgICB0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IkF2ZW5pciIsIHNpemU9dGV4dHN6KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBzaXplPXRleHRzeioxLjIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUsIHZqdXN0PS00KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41LCB2anVzdD0xLjQpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uPSJyaWdodCIsCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oLTUwLCAzLCAwLCAwKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPXRleHRzeiowLjk1KSwKICAgICAgICBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgyMCwgInB0IikKICAgICAgICApICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKGhhbWxpbmVfcmVkLCBtaWFjX2dyZWVuKSkKI2Rldi5vZmYoKQpgYGAKClxoZmlsbCBcYnJlYWsKXGhmaWxsIFxicmVhawoKV2hpbGUgSGFtbGluZSdzIGVucm9sbG1lbnQgZmVsbCBzdGVhZGlseSwgZW5yb2xsbWVudCBudW1iZXJzIHN0YXllZCByZWxhdGl2ZWx5IHN0YWJsZSB0aHJvdWdob3V0IHRoZSByZXN0IG9mIHRoZSBNSUFDLiBBcyBhIHJlc3VsdCwgdGhlIHBvcnRpb24gb2Ygc3R1ZGVudHMgaW4gdGhlIE1JQUMgd2hvIGF0dGVuZGVkIEhhbWxpbmUgYWxzbyByZWxpYWJseSBkZWNyZWFzZWQgeWVhciBhZnRlciB5ZWFyLgoKXGhmaWxsIFxicmVhawpcaGZpbGwgXGJyZWFrCgoKIyMgVGhlIFNocmlua2luZyBQb3J0aW9uIG9mIE1JQUMgU3R1ZGVudHMgQXR0ZW5kaW5nIEhhbWxpbmUgU2luY2UgMjAxMgoKYGBge3J9CgpzY2hvb2xDb2xzID0gYygiIzY2NjY2NiIsICIjMDA2OWFhIiwgIiMwYjUwOTEiLCAiI2JlMGYzNCIsICIjRTZCMjIwIiwgIiNGRkYiLCBoYW1saW5lX3JlZCwgCiAgICAgICAgICAgICAgICIjRDQ0NDIwIiwgIiMwMDAiLCAiI0UyMjczOSIsICIjNEYyNjgyIiwgIiM1MzU4NWEiLCAiIzAwNDQ3YyIpCnNjaG9vbENvbHMyID0gYygiIzY2MDAzMyIsIiNCMDkyNDciLCIjRkZEMjRGIiwgIiMwMDAiLCAiIzAwMzA1NSIsIiNGQ0NCMDYiLCAiIzg4OEM4RCIsIAogICAgICAgICAgICAgICAgIiMwMTQyNkEiLCAiI0ZGRkZGRSIsICIjMEMyRjU5IiwgIiNGRkUxNTMiLCAiIzI0MjEyMSIsICIjRkZDQjAwIikKCmF2YWwgPC0gbGlzdCgpCmZvcihzdGVwIGluIDE6MTApIHsKICB5ciA9IHN0ZXArMjAxMQogIGF2YWxbW3N0ZXBdXSA8LWxpc3QodmlzaWJsZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IHBhc3RlMCgnWWVhciA9ICcsIHlyKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0geXIsCiAgICAgICAgICAgICAgICAgICAgICB4PSh5clBvcCAlPiUgZmlsdGVyKFllYXI9PXlyKSAlPiUgYXJyYW5nZShTY2hvb2wpKSRTY2hvb2wsCiAgICAgICAgICAgICAgICAgICAgICB5PSh5clBvcCAlPiUgZmlsdGVyKFllYXI9PXlyKSAlPiUgYXJyYW5nZShTY2hvb2wpKSRQb3B1bGF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgdGV4dD0oeXJQb3AgJT4lIGZpbHRlcihZZWFyPT15cikgJT4lIGFycmFuZ2UoU2Nob29sKSkkUG9ydGlvbikKfQphdmFsWzNdW1sxXV0kdmlzaWJsZSA9IFQKCnN0ZXBzIDwtIGxpc3QoKQpmaWcgPC0gcGxvdF9seShzb3J0PUYpCmZvciAoaSBpbiAxOjEwKSB7CiAgeXIgPSBpKzIwMTEKICBmaWcgPSBmaWcgJT4lIGFkZF9waWUobGFiZWxzPWF2YWxbaV1bWzFdXSR4LCAKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWF2YWxbaV1bWzFdXSR5LAogICAgICAgICAgICAgICAgICAgICAgICAjdGV4dD1hdmFsW2ldW1sxXV0keCwKICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZSA9IGF2YWxbaV1bWzFdXSR2aXNpYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvcnM9c2Nob29sQ29scywgbGluZT1saXN0KGNvbG9yPXNjaG9vbENvbHMyLCB3aWR0aD0yKSksCiAgICAgICAgICAgICAgICAgICAgICAgIHB1bGwgPSAwLjAzLAogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gJycsI2F2YWxbaV1bWzFdXSRuYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICdwaWUnLCAKICAgICAgICAgICAgICAgICAgICAgICAgaG92ZXJpbmZvID0gJ3RleHQnLAogICAgICAgICAgICAgICAgICAgICAgICBob3ZlcnRleHQgPSBwYXN0ZSgKICAgICAgICAgICAgICAgICAgICAgICAgICBhdmFsW2ldW1sxXV0keCwgJ1xuJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVzOjpwZXJjZW50KGF2YWxbaV1bWzFdXSR0ZXh0LCBhY2N1cmFjeT0wLjAxKSwgJ29mIHRoZSBNSUFDXG4nLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBhdmFsW2ldW1sxXV0keSwgIlN0dWRlbnRzIgogICAgICAgICAgICAgICAgICAgICAgICApKQoKICBzdGVwIDwtIGxpc3QoYXJncyA9IGxpc3QoJ3Zpc2libGUnLCByZXAoRkFMU0UsIGxlbmd0aChhdmFsKSkpLAogICAgICAgICAgICAgICBtZXRob2QgPSAncmVzdHlsZScsIGxhYmVsPXlyKQogIHN0ZXAkYXJnc1tbMl1dW1tpXV0gPSBUUlVFICAKICBzdGVwc1tbaV1dID0gc3RlcCAKfSAKCmZpZyA8LSBmaWcgJT4lCiAgbGF5b3V0KHNsaWRlcnMgPSBsaXN0KGxpc3QoYWN0aXZlID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50dmFsdWUgPSBsaXN0KHByZWZpeCA9ICJZZWFyOiAiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwcyA9IHN0ZXBzKSkpCgpmaWcKYGBgCgpMaWtlIGVtaWdyYXRpb24gZnJvbSBhIGNvdW50cnksIHRoZSBzaXplIG9mIHRoZSBzdHVkZW50IHBvcHVsYXRpb24gYXQgSGFtbGluZSBzaG91bGQgYmUgdW5kZXJzdG9vZCBhcyBjb21wbGljYXRlZCBhbmQgYWZmZWN0ZWQgc3VidGx5IGJ5IG1hbnkgZmFjdG9yczogc29tZSBwb3NpdGl2ZSBhbmQgc29tZSBuZWdhdGl2ZS4gVGhvc2UgZmFjdG9ycyBpbmNsdWRlLCBidXQgYXJlIG5vdCBsaW1pdGVkIHRvLCB0aGUgbnVtYmVyIG9mIGFwcGxpY2F0aW9ucywgYWNjZXB0YW5jZSByYXRlLCBlbnJvbGxtZW50IHJhdGUgKGFtb25nIHRob3NlIHdobyBoYXZlIGJlZW4gYWRtaXR0ZWQpLCB0cmFuc2ZlcnMtaW4sIHRyYW5zZmVycy1vdXQsIGFuZCB3aXRoZHJhd2FsIHJhdGVzLiBQdXQgbW9yZSBzaW1wbHk6IGhvdyBtYW55IGFyZSBjb21pbmcgaW4sIGhvdyBtYW55IGFyZSBjb21pbmcgYmFjaywgYW5kIGhvdyBtYW55IGFyZSBsZWF2aW5nPwoKVW5pdmVyc2l0aWVzIHVzZSBhIGZhaXJseSBzdHJpY3RseS1kZWZpbmVkIG1ldHJpYywgKnJldGVudGlvbiosIHRvIHF1YW50aWZ5IHRoZSAiSG93IG1hbnkgYXJlIGNvbWluZyBiYWNrPyIgcG9ydGlvbiBvZiB0aGF0IGVxdWF0aW9uLiBSYXRoZXIgdGhhbiBtb3JlIGdlbmVyYWxseSB0cmFja2luZyB0aGUgcG9ydGlvbiBvZiBzdHVkZW50cyBpbiBhIGdpdmVuIHNlbWVzdGVyIHdobyBhbHNvIGF0dGVuZGVkIHRoZSBzYW1lIHNjaG9vbCBpbiB0aGUgcHJldmlvdXMgc2VtZXN0ZXIsIHRoZSBOYXRpb25hbCBDZW50ZXIgZm9yIEVkdWNhdGlvbiBTdGF0aXN0aWNzIHNwZWNpZmljYWxseSB0cmFja3MgdGhlIHBvcnRpb24gb2YgYSB1bml2ZXJzaXR5J3MgZmlyc3QtdGltZSBzdHVkZW50cyBpbiB0aGUgZmFsbCBzZW1lc3RlciBvZiB0aGVpciBmaXJzdCB5ZWFyICh0aGF0IHllYXIncyAiY29ob3J0Iikgd2hvIHJldHVybiBpbiBzdWJzZXF1ZW50IHNlbWVzdGVycy5eW1doZXJldmVyIGFuIGluZGl2aWR1YWwgKnJldGVudGlvbiogZmlndXJlIGlzIHJlcG9ydGVkIGZvciBhIHVuaXZlcnNpdHksIGl0IGdlbmVyYWxseSByZWZlcnMgdG8gdGhlIHBvcnRpb24gb2YgdGhlIHByZXZpb3VzIHllYXIncyBjb2hvcnQgd2hvIHJldHVybmVkIGZvciB0aGUgZmFsbCBzZW1lc3RlciBvZiB0aGVpciBzZWNvbmQgeWVhci5dCgpMb29raW5nIGF0IEhhbWxpbmUncyBvZmZpY2lhbGx5IHJlcG9ydGVkIHJldGVudGlvbiByYXRlcyBzaW5jZSAyMDA2LCB3ZSBjYW4gc2VlIGEgZGlzdGluY3QgY2hhbmdlOiBsb25nLXRlcm0gcmV0ZW50aW9uIGhhcyBmYWxsZW4sIGFuZCB0aGUgc2l6ZSBvZiB0aGUgY29ob3J0IGhhcyBncm93bi4gTW9zdCBub3RhYmx5LCB0aGUgY29ob3J0IHNpemUgZ3JldyBieSAqMzUlKiBmcm9tIDIwMDkgdG8gMjAxMiB3aGlsZSB0aGUgZm91ci15ZWFyIHJldGVudGlvbiByYXRlIGZlbGwgZnJvbSA1OCUgdG8gNTQuMyUgb3ZlciB0aGF0IHNhbWUgcGVyaW9kLiBUaG91Z2ggdGhhdCBjaGFuZ2UgcHJlY2VkZXMgTWlsbGVyJ3MgdGVybSwgdGhlIHRyZW5kIGNvbnRpbnVlZCB0aHJvdWdob3V0IHRoZSBhdmFpbGFibGUgZGF0YS4KCiMjIENoYW5nZSBpbiBTdHVkZW50IFJldGVudGlvbiBhdCBIYW1saW5lLCAyMDA2LTIwMTkKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpwX3RvX24gPSBmdW5jdGlvbihwZXJpb2QpIHsKICBjb252ZXJ0ZXIgPSBsaXN0KCkKICBjb252ZXJ0ZXJbIkZhbGwxIl0gPSAxCiAgY29udmVydGVyWyJGYWxsMiJdID0gMwogIGNvbnZlcnRlclsiRmFsbDMiXSA9IDUKICBjb252ZXJ0ZXJbIkZhbGw0Il0gPSA3CiAgY29udmVydGVyWyJTcHJpbmcxIl0gPSAyCiAgY29udmVydGVyWyJTcHJpbmcyIl0gPSA0CiAgY29udmVydGVyWyJTcHJpbmczIl0gPSA2CiAgY29udmVydGVyWyJTcHJpbmc0Il0gPSA4CiAgb3V0ID0gYygpCiAgZm9yIChpIGluIHBlcmlvZCkgewogICAgb3V0ID0gYyhvdXQsIGNvbnZlcnRlcltbaV1dKQogIH0KICByZXR1cm4ob3V0KQp9CgpyZXQyID0gcmV0ZW50aW9uICU+JSBtdXRhdGVfYWxsKC5mdW5zPWFzLm51bWVyaWMpICU+JSByZW5hbWUoRmFsbDFOID0gQ29ob3J0KSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9LWMoWWVhciksIG5hbWVzX3RvPSJQZXJpb2QiLCB2YWx1ZXNfdG89IlJldGFpbmVkIikgJT4lIAogIG11dGF0ZShpc1BjdCA9ICFzdHJfZW5kcyhQZXJpb2QsICJOIiksIHBjdCA9IFJldGFpbmVkKmlzUGN0LCBQZXJpb2QgPSBzdHJfcmVwbGFjZV9hbGwoUGVyaW9kLCAiTiIsICIiKSwgbz1wX3RvX24oUGVyaW9kKSkgJT4lCiAgZ3JvdXBfYnkoWWVhciwgbykgJT4lIHN1bW1hcml6ZShwY3Q9bWF4KHBjdCksIGN0PW1heChSZXRhaW5lZCkpICAlPiUgbXV0YXRlKHBjdD1pZmVsc2UocGN0PT0wLCAxLCBwY3QpKQoKZ2cgPSByZXQyICU+JSBmaWx0ZXIoWWVhcj09MjAwNikgJT4lCiAgZ2dwbG90KGFlcyh4PW8sIHk9Y3QpKSArIGdlb21fYmFyKGFlcyhhbHBoYT1wY3QpLCBzdGF0PSJpZGVudGl0eSIsIGZpbGw9aGFtbGluZV9yZWQpICsgY29vcmRfZmxpcCgpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlPWMoMC43LCAxKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9KDE6OCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiMXN0IEZhbGwiLCAiMXN0IFNwcmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIybmQgRmFsbCIsICIybmQgU3ByaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjNyZCBGYWxsIiwgIjNyZCBTcHJpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNHRoIEZhbGwiLCAiNHRoIFNwcmluZyIpKSArIAogIGxhYnMoeT0iRnVsbC1UaW1lIFN0dWRlbnRzIFJldGFpbmVkIiwgeD0iU2VtZXN0ZXJzIGF0IEhhbWxpbmUiLCB0aXRsZT0iUmVudGlvbiBhdCBIYW1saW5lIikgKyAKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKSArIGd1aWRlcyhhbHBoYT0ibm9uZSIpCgphdmFsIDwtIGxpc3QoKQpmb3Ioc3RlcCBpbiAxOjE0KSB7CiAgeXIgPSBzdGVwKzIwMDUKICBhdmFsW1tzdGVwXV0gPC1saXN0KHZpc2libGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBwYXN0ZTAoJ1llYXIgPSAnLCB5ciksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHlyLAogICAgICAgICAgICAgICAgICAgICAgcGQ9YygiMXN0IEZhbGwgU2VtZXN0ZXIiLCAiMXN0IFNwcmluZyBTZW1lc3RlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMm5kIEZhbGwgU2VtZXN0ZXIiLCAiMm5kIFNwcmluZyBTZW1lc3RlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiM3JkIEZhbGwgU2VtZXN0ZXIiLCAiM3JkIFNwcmluZyBTZW1lc3RlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNHRoIEZhbGwgU2VtZXN0ZXIiLCAiNHRoIFNwcmluZyBTZW1lc3RlciIpLAogICAgICAgICAgICAgICAgICAgICAgeD0xOjgsCiAgICAgICAgICAgICAgICAgICAgICB5PShyZXQyICU+JSBmaWx0ZXIoWWVhcj09eXIpKSRjdCwKICAgICAgICAgICAgICAgICAgICAgIGFscGhhPShyZXQyICU+JSBmaWx0ZXIoWWVhcj09eXIpKSRwY3QpCn0KYXZhbFsxXVtbMV1dJHZpc2libGUgPSBUCgpzdGVwcyA8LSBsaXN0KCkKZmlnIDwtIHBsb3RfbHkoKQpmb3IgKGkgaW4gMToxNCkgewogIHlyID0gaSsyMDA1CiAgZmlnID0gZmlnICU+JSBhZGRfYmFycyh5PWF2YWxbaV1bWzFdXSRwZCwgeD1hdmFsW2ldW1sxXV0keSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0PXNjYWxlczo6cGVyY2VudChhdmFsW2ldW1sxXV0kYWxwaGEpLAogICAgICAgICAgICAgICAgICAgICAgICAgI29wYWNpdHkgPSBhdmFsW2ldW1sxXV0kYWxwaGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvcj1oYW1saW5lX3JlZCwgb3BhY2l0eSA9IGF2YWxbaV1bWzFdXSRhbHBoYS8yKzAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmxlID0gYXZhbFtpXVtbMV1dJHZpc2libGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICcnLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAnYmFyJywgCiAgICAgICAgICAgICAgICAgICAgICAgICBob3ZlcmluZm8gPSAndGV4dCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBob3ZlcnRleHQgPSBwYXN0ZShhdmFsW2ldW1sxXV0keSwgInN0dWRlbnRzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbj0gJ2gnLCBzaG93bGVnZW5kPUYpCgogIHN0ZXAgPC0gbGlzdChhcmdzID0gbGlzdCgndmlzaWJsZScsIHJlcChGQUxTRSwgbGVuZ3RoKGF2YWwpKSksCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICdyZXN0eWxlJywgbGFiZWw9eXIpCiAgc3RlcCRhcmdzW1syXV1bW2ldXSA9IFRSVUUgIAogIHN0ZXBzW1tpXV0gPSBzdGVwIAp9IAoKCmZpZyA9IGZpZyAlPiUKICBsYXlvdXQoc2xpZGVycyA9IGxpc3QobGlzdChhY3RpdmUgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnR2YWx1ZSA9IGxpc3QocHJlZml4ID0gIlllYXI6ICIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXBzID0gc3RlcHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkID0gbGlzdCh0PTYwKSkpLAogICAgICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZT0iRnVsbC1UaW1lIFN0dWRlbnRzIFJldGFpbmVkIGZyb20gRmlyc3QtWWVhciBDb2hvcnQiLCByYW5nZT1jKDAsIDYwMCkpLAogICAgICAgICBtYXJnaW4gPSBsaXN0KHBhZD0xMCkKKSAKCmZpZwoKCmBgYAoKIyBBY2FkZW1pYyBQcm9ncmFtcwoKQW5lY2RvdGFsbHksIG15IGNvbnZlcnNhdGlvbnMgd2l0aCBIYW1saW5lIHByb2Zlc3NvcnMgYWJvdXQgTWlsbGVyJ3MgYWRtaW5pc3RyYXRpb24gaGF2ZSB0ZW5kZWQgdG93YXJkIGFpcmluZyBvdXQgZnJ1c3RyYXRpb25zIHdpdGggc2V2ZXJhbCB5ZWFycyBvZiAicmlnaHRzaXppbmciIGFuZCAicHJvZ3JhbSByZXZpZXciIHdoaWNoIGFpbWVkIHRvIHJlZHVjZSBleHBlbnNlcyBieSByZW1vdmluZyBvciByZXN0cmljdGluZyBhY2FkZW1pYyBwcm9ncmFtcyB3aXRoIGxpbWl0ZWQgYXR0ZW5kYW5jZSBvciBsaW1pdGVkIGZpbmFuY2lhbCByZXR1cm5zLiBXaGlsZSB0aGVpciBjb21wbGFpbnRzIGFyZSBvZnRlbiBxdWFsaXRhdGl2ZS0tLWluY2x1ZGluZyBhIHNlbnNlIG9mIGpvYiBpbnNlY3VyaXR5IGFuZCBpbnRlcmRlcGFydG1lbnRhbCB0ZW5zaW9uIG92ZXIgdGhlaXIgc2hhcmVkLCBzY2FudCByZXNvdXJjZXMtLS13ZSB3aWxsIHByb2NlZWQgd2l0aCBvbmUgY29hcnNlIGFwcHJvYWNoIGZvciBxdWFudGlmeWluZyB0aGlzIHVwaGVhdmFsLgoKSSBnYXRoZXJlZCBkYXRhIGZyb20gdGhlIFVuaXZlcnNpdHkncyBidWxsZXRpbnMgdG8gdGFidWxhdGUgdGhlIEFjYWRlbWljIFByb2dyYW1zIG9mZmVyZWQgZm9yIGVhY2ggb2YgdGhlIHBhc3QgMTQgeWVhcnMuIEJ5IGNvbXBhcmluZyBlYWNoIHllYXIgdG8gdGhlIHByZXZpb3VzIHllYXIsIHdlIGNhbiBzZWUgaG93IG1hbnkgcHJvZ3JhbXMgd2VyZSAqYWRkZWQqIGFuZCBob3cgbWFueSB3ZXJlICpyZW1vdmVkKi4KClRoZXJlIGFyZSBpbXBvcnRhbnQgbGltaXRzIHRvIHRoZXNlIGRhdGEgd2hpY2ggc2hvdWxkIGJlIGNvbnNpZGVyZWQ6IHRoZSBjb21wYXJpc29uIGJldHdlZW4geWVhcnMgcmVsaWVzIGVudGlyZWx5IG9uIHRoZSBsaXRlcmFsIG5hbWVzIG9mIHRoZSBwcm9ncmFtcyBvZmZlcmVkLiBJZiBhICJCYWNoZWxvciBvZiBBcnRzIGluIFB1YmxpYyBIZWFsdGgiIGlzIHJlbGFiZWxlZCBhcyBhICJCYWNoZWxvciBvZiBBcnRzIChCQSkgaW4gUHVibGljIEhlYWx0aCIgdGhlIG5leHQgeWVhciwgdGhhdCBpcyBjb3VudGVkIGFzIGJvdGggMSBwcm9ncmFtIGxvc3QgYW5kIDEgcHJvZ3JhbSBnYWluZWQuIFN0aWxsLCBhbiBpbWJhbGFuY2Ugb2YgcHJvZ3JhbSBjaGFuZ2VzIHNpZ25pZmllcyBhIHRydWUgbG9zcyBvciBnYWluIG9mIGEgcHJvZ3JhbSwgYW5kIG1hbnkgbmFtZSBjaGFuZ2VzICpkbyogcmVmbGVjdCBhIHJlYWwsIHN1YnN0YW50aXZlIGNoYW5nZSB0byB0aGUgcHJvZ3JhbS4gCgpTaW5jZSBNaWxsZXIncyB0ZXJtIGJlZ2FuLCB3ZSBjYW4gc2VlIGEgY2xlYXIsIG5ldyB0cmVuZCBvZiBncm93aW5nIHVwaGVhdmFsIGluIHRoZSBwcm9ncmFtcyBvZmZlcmVkIGF0IEhhbWxpbmUuCgojIyBZZWFybHkgY2hhbmdlIGluIHRoZSBudW1iZXIgb2YgYWNhZGVtaWMgcHJvZ3JhbXMgYXQgSGFtbGluZSBzaW5jZSAyMDA5CgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTguOH0KCnByb2dyYW1zICU+JSBzZWxlY3QoLWMoY2VydCwgbWFqb3IsIG1pbm9yLCBwcmVwLCBsaWNlbnNlLCBkaXBsb21hKSkgJT4lIAogIGxlZnRfam9pbihwcm9ncmFtcyAlPiUgZ3JvdXBfYnkobmFtZSkgJT4lIHN1bW1hcml6ZShzID0gbWluKHlyKSwgZT1tYXgoeXIpKSkgJT4lIAogIGdyb3VwX2J5KG5hbWUpICU+JSBzdW1tYXJpemUoU3RhcnRlZD1zWzFdLCBFbmRlZD1lWzFdKSAlPiUKICBtdXRhdGUoZm09U3RhcnRlZD4yMDE0KSAlPiUKICBwaXZvdF9sb25nZXIoY29scz1jKFN0YXJ0ZWQsIEVuZGVkKSwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJkdCIpICU+JQogIGZpbHRlcihkdCA+IDIwMDgsIGR0PDIwMjMpICU+JQogIGdyb3VwX2J5KGR0LCB0eXBlKSAlPiUgc3VtbWFyaXplKGFtdD1sZW5ndGgoZHQpKSAlPiUKICBtdXRhdGUoYW10ID0gaWZlbHNlKHR5cGU9PSJFbmRlZCIsIC1hbXQsIGFtdCksIAogICAgICAgICB0eXBlID0gZmFjdG9yKHR5cGUsIGxldmVscz1jKCJTdGFydGVkIiwgIkVuZGVkIiksIGxhYmVscz1jKCJQcm9ncmFtcyBTdGFydGVkIiwgIlByb2dyYW1zIEVuZGVkIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZHQsIHk9YW10LCBmaWxsPXR5cGUpKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MjAxNS41LCBsaW5ldHlwZT0iZGFzaGVkIikgKwogIGdlb21fdGV4dCh4PTIwMTUuNywgeT0tMzgsIGxhYmVsPSJQcmVzaWRlbnQgTWlsbGVyJ3MgRmlyc3QgVGVybSIsIGFuZ2xlPTkwLCBmYW1pbHk9IkF2ZW5pciIsIGZhY2U9Iml0YWxpYyIsIHNpemU9dGV4dHN6KjAuMjgpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMjAwOToyMDIyKSwgbGFiZWxzPWMoIicwOSIsICInMTAiLCAiJzExIiwgIicxMiIsICInMTMiLCAiJzE0IiwgIicxNSIsICInMTYiLCAiJzE3IiwgIicxOCIsICInMTkiLCAiJzIwIiwgIicyMSIsICInMjIiKSkgKwogIGxhYnMoeD0iWWVhciIsIHk9IkNoYW5nZSBpbiB0aGUgbnVtYmVyIG9mIGFjYWRlbWljIHByb2dyYW1zIiwgZmlsbD0iIikgKyB0aGVtZV9taW5pbWFsKCkgKyAKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQobnJvdz0yLCBieXJvdz1UKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KCB2anVzdD0xKSwKICAgICAgICB0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IkF2ZW5pciIsIHNpemU9dGV4dHN6KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBzaXplPXRleHRzeioxLjIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUsIHZqdXN0PS00KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3Q9MS41LCB2anVzdD0xLjQpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uPSJyaWdodCIsCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oLTUwLCAzLCAwLCAwKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPXRleHRzeiowLjk1KSwKICAgICAgICBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgyMCwgInB0IikKICAgICAgICApICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwgaGFtbGluZV9yZWQpKQoKYGBgCgojIEZpbmFuY2VzCgpMYXN0bHksIEkgZXhwbG9yZWQgSGFtbGluZSdzIGZpbmFuY2VzIHNpbmNlIDIwMTIuCgpEZXNwaXRlIHRoZSByZWxpYWJsZSBmcnVzdHJhdGlvbiBpbiByZXNwb25zZSB0byBIYW1saW5lJ3MgYW5udWFsIHR1aXRpb24gaW5jcmVhc2UgYW5ub3VuY2VtZW50LCBuZWFybHkgZXZlcnkgdW5pdmVyc2l0eSByYWlzZXMgaXRzIHR1aXRpb24geWVhciBhZnRlciB5ZWFyLiBTdGlsbCwgdGhlIHVuaXZlcnNpdHkncyBmaW5hbmNpYWwgc3RhYmlsaXR5IGhhcyBiZWVuIGEgbWFqb3IgY29uY2VybiBzaW5jZSBiZWZvcmUgTWlsbGVyJ3MgcHJlc2lkZW5jeSwgYW5kIHdpdGggYSBzaXphYmxlIGJ1ZGdldCBkZWZpY2l0IGxvb21pbmcgb3ZlciBjYW1wdXMsIHRoaXMgTWlsbGVyJ3MgZmluYWwgeWVhciBsb29rcyBubyBkaWZmZXJlbnQuCgpXaGVuIEkgaW50ZXJ2aWV3ZWQgUHJlc2lkZW50IE1pbGxlciBvbiBOb3YuIDMwLCAyMDIzLCBzaGUgY29uZmlybWVkIHRoYXQgdGhlIGFubnVhbCB0dWl0aW9uIGNoYW5nZSBpcyBwYXJ0IG9mIEhhbWxpbmUgYmVpbmcgYSAidHVpdGlvbi1mdW5kZWQgVW5pdmVyc2l0eSIgYWZmZWN0ZWQgYnkgaW5mbGF0aW9uIGFuZCBkZWNsaW5pbmcgZW5yb2xsbWVudCBhbmQgdGhhdCBzaGUgaGFkIHByaW9yaXRpemVkIGdyb3dpbmcgdGhlIHNjaG9vbCdzIGVuZG93bWVudCB0aHJvdWdob3V0IGhlciB0ZXJtLgoKVGhlIGZpbmFuY2lhbCByZXBvcnRzIG9mIHByaXZhdGUsIG5vbi1wcm9maXQgdW5pdmVyc2l0aWVzIGxpa2UgSGFtbGluZSBhcmUgcHVibGljXltUaG91Z2ggdGhlcmUgaXMgb2Z0ZW4gYSBsZW5ndGh5IChtdWx0aS15ZWFyKSBkZWxheSBiZXR3ZWVuIGEgeWVhcidzIHRheCBzZWFzb24gYW5kIHB1YmxpYyBhY2Nlc3MgdG8gdGhlIDk5MCBmb3JtLl0uIFRoaXMgZm9ybSBpbmNsdWRlcyBhbiBpdGVtaXplZCBsaXN0IG9mIG1ham9yIGV4cGVuc2VzIHdoaWNoIGFyZSB0b3RhbGVkIGludG8gYSBzaW5nbGUgIlRvdGFsIEV4cGVuc2VzIiBmaWVsZC4gV2hlbiB0aGF0IG51bWJlciBpcyBkaXZpZGVkIGJ5IHRoZSB1bml2ZXJzaXR5J3MgcmVwb3J0ZWQgZW5yb2xsbWVudCwgd2UgYXJyaXZlIGF0IGFuIGFwcHJveGltYXRlZCAqRXhwZW5zZXMgUGVyIFN0dWRlbnQqIHdoaWNoIG1pZ2h0IHJlYXNvbmFibHkgYmUgZXhwZWN0ZWQgdG8gY29ycmVsYXRlIHdpdGggd2hhdCB0aGUgdW5pdmVyc2l0eSBjaGFyZ2VzIGZvciB0dWl0aW9uLiBJbiB0aGUgTUlBQyBhdCBsYXJnZSwgaXQgZG9lcy4gQXQgSGFtbGluZSwgZGVzcGl0ZSBkZWNsaW5pbmcgZW5yb2xsbWVudCBudW1iZXJzLCB0aGUgcmVwb3J0ZWQgKkV4cGVuc2VzIFBlciBTdHVkZW50KiBmZWxsIGZyb20gbW9yZSB0aGFuIFwkNDBrIHRvIGxlc3MgdGhhbiAqXCQyNWsqIHdoaWxlIHR1aXRpb24gc3RlYWRpbHkgY2xpbWJlZCBwYXN0IFwkNDBrLiBXaGVyZSBpcyBhbGwgdGhhdCBtb25leSBnb2luZz8KCgojIyBSZXBvcnRlZCBFeHBlbnNlcyBQZXIgU3R1ZGVudCB2cyBUdWl0aW9uIAoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD04fQpwMSA9IHBjICU+JSBzZWxlY3QoU2Nob29sLCBUb3RhbEV4cGVuc2VzLCBZZWFyKSAlPiUgCiAgZ3JvdXBfYnkoU2Nob29sLCBZZWFyKSAlPiUgZmlsdGVyKFllYXIgPCAyMDIxKSAlPiUgc3VtbWFyaXplKFNjaG9vbD1TY2hvb2xbMV0sIFllYXI9WWVhclsxXSwgVG90YWxFeHBlbnNlcz1Ub3RhbEV4cGVuc2VzWzFdKSAlPiUgCiAgbXV0YXRlKFBvcCA9IGFzLm51bWVyaWMoZ2V0UG9wKFNjaG9vbCwgWWVhcikpLCAKICAgICAgICAgRXhwZW5zZVBlclN0dWRlbnQ9VG90YWxFeHBlbnNlcy9Qb3AsIAogICAgICAgICBpc0hVID0gaWZlbHNlKFNjaG9vbD09IkhVIiwgIkhhbWxpbmUiLCAiTUlBQyIpKSAlPiUgCiAgZ3JvdXBfYnkoaXNIVSwgWWVhcikgJT4lIHN1bW1hcml6ZShFeHBlbnNlUGVyU3R1ZGVudCA9IG1lYW4oRXhwZW5zZVBlclN0dWRlbnQpKSAlPiUgbGVmdF9qb2luKHR1aXRzICU+JSBmaWx0ZXIoaXNIVT09IkhhbWxpbmUiKSkgJT4lCiAgZmlsdGVyKGlzSFU9PSJIYW1saW5lIikgJT4lCiAgZ2dwbG90KGFlcyh4PVllYXIsIHk9RXhwZW5zZVBlclN0dWRlbnQpKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3M9MjAxMjoyMDIwKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWFtdCksIGxpbmV0eXBlPSJkYXNoZWQiLCBsaW5ld2lkdGg9NCwgZmlsbD0iIzlkMjIzNSIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgZ2VvbV9hcmVhKGxpbmV3aWR0aD00LCBmaWxsPSJkYXJrZ3JheSIsIGFscGhhPTAuOCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX2RvbGxhcigpLCBsaW1pdHM9YygwLCA1MDAwMCkpICsKICBnZW9tX3RleHQoeD0yMDE2LCB5PTEwMDAwLCBsYWJlbD0iVG90YWwgdW5pdmVyc2l0eSBleHBlbnNlcyBwZXIgc3R1ZGVudCIsIGZhbWlseT0iQXZlbmlyIiwgc2l6ZT10ZXh0c3oqMC4yNSkgKwogIGdlb21fdGV4dCh4PTIwMTgsIHk9MzUwMDAsIGxhYmVsPSJIYW1saW5lIHVuaXZlcnNpdHkgaW4tc3RhdGUgdHVpdGlvbiIsIGNvbD0id2hpdGUiLCBmYW1pbHk9IkF2ZW5pciIsIHNpemU9dGV4dHN6KjAuMjUpICsgCiAgbGFicyh5PSJDb3N0IG9mIHR1aXRpb24gYW5kIGNvc3Qgb2YgdW5pdmVyc2l0eSBleHBlbnNlcyAoVVNEKVxuIiwgeD0iXG5ZZWFyIiwgdGl0bGU9IlR1aXRpb24gdnMuIHVuaXZlcnNpdHkgZXhwZW5zZXMgcGVyIHN0dWRlbnQgYXQgSGFtbGluZSBVbml2ZXJzaXR5IikgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZT0iYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJBdmVuaXIiLCBzaXplPXRleHRzeiowLjYpKQoKcDIgPSBwYyAlPiUgc2VsZWN0KFNjaG9vbCwgVG90YWxFeHBlbnNlcywgWWVhcikgJT4lIAogIGdyb3VwX2J5KFNjaG9vbCwgWWVhcikgJT4lIGZpbHRlcihZZWFyIDwgMjAyMSkgJT4lIHN1bW1hcml6ZShTY2hvb2w9U2Nob29sWzFdLCBZZWFyPVllYXJbMV0sIFRvdGFsRXhwZW5zZXM9VG90YWxFeHBlbnNlc1sxXSkgJT4lIAogIG11dGF0ZShQb3AgPSBhcy5udW1lcmljKGdldFBvcChTY2hvb2wsIFllYXIpKSwgCiAgICAgICAgIEV4cGVuc2VQZXJTdHVkZW50PVRvdGFsRXhwZW5zZXMvUG9wLCAKICAgICAgICAgaXNIVSA9IGlmZWxzZShTY2hvb2w9PSJIVSIsICJIYW1saW5lIiwgIk1JQUMiKSkgJT4lIAogIGdyb3VwX2J5KGlzSFUsIFllYXIpICU+JSBzdW1tYXJpemUoRXhwZW5zZVBlclN0dWRlbnQgPSBtZWFuKEV4cGVuc2VQZXJTdHVkZW50KSkgJT4lIGxlZnRfam9pbih0dWl0cyAlPiUgbXV0YXRlKGlzSFUhPSJIYW1saW5lIikpICU+JQogIGdyb3VwX2J5KGlzSFUsIFllYXIpICU+JSBzdW1tYXJpemUoRXhwZW5zZVBlclN0dWRlbnQgPSBtZWFuKEV4cGVuc2VQZXJTdHVkZW50KSwgYW10PW1lYW4oYW10KSkgJT4lCiAgZmlsdGVyKGlzSFUhPSJIYW1saW5lIikgJT4lCiAgZ2dwbG90KGFlcyh4PVllYXIsIHk9RXhwZW5zZVBlclN0dWRlbnQpKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3M9MjAxMjoyMDIwKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgZ2VvbV9hcmVhKGxpbmV3aWR0aD00LCBmaWxsPSJkYXJrZ3JheSIsIGFscGhhPTAuOCkgKwogIGdlb21fYXJlYShhZXMoeT1hbXQpLCBsaW5ldHlwZT0iZGFzaGVkIiwgbGluZXdpZHRoPTQsIGZpbGw9IiMwZjc3NTQiKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX2RvbGxhcigpLCBsaW1pdHM9YygwLCA1MDAwMCkpICsKICBnZW9tX3RleHQoeD0yMDE0LjYsIHk9NDEwMDAsIGxhYmVsPSJNZWFuIHRvdGFsIHVuaXZlcnNpdHkgZXhwZW5zZXMgcGVyIHN0dWRlbnQiLCBmYW1pbHk9IkF2ZW5pciIsIHNpemU9dGV4dHN6KjAuMjUpICsKICBnZW9tX3RleHQoeD0yMDE2LCB5PTIwMDAwLCBsYWJlbD0iTUlBQyBtZWFuIGluLXN0YXRlIHR1aXRpb24iLCBjb2w9IndoaXRlIiwgZmFtaWx5PSJBdmVuaXIiLCBzaXplPXRleHRzeiowLjI1KSArIAogIGxhYnMoeT0iQ29zdCBvZiB0dWl0aW9uIGFuZCBjb3N0IG9mIHVuaXZlcnNpdHkgZXhwZW5zZXMgKFVTRClcbiIsIHg9IlxuWWVhciIsIHRpdGxlPSJUdWl0aW9uIHZzLiB1bml2ZXJzaXR5IGV4cGVuc2VzIHBlciBzdHVkZW50IGluIHRoZSBNSUFDIikgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZT0iYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJBdmVuaXIiLCBzaXplPXRleHRzeiowLjYpKQoKCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2w9MikKYGBgCgpUaGUgTUlBQyBzY2hvb2xzIHZhcnkgc2lnbmlmaWNhbnRseSwgYW5kIHRoYXQgaW4gdHVybiBsaW1pdHMgdGhlIG1lYW5pbmcgb2YgYW55IGRpcmVjdCBjb21wYXJpc29uIG9mIHRoZSBkb2xsYXIgYW1vdW50IG9mIGFkbWluaXN0cmF0aXZlIHNhbGFyaWVzIGF0IGRpZmZlcmVudCBzY2hvb2xzLiBIb3dldmVyLCBGb3JtIDk5MCBhbHNvIGluY2x1ZGVzIGEgcmVwb3J0IG9mICphbGwgY29tcGVuc2F0aW9uIHBhaWQgdG8gdW5pdmVyc2l0eSBlbXBsb3llZXMqLiBCeSBpbnN0ZWFkIGNvbXBhcmluZyB0aGUgcG9ydGlvbiBvZiBhbGwgdW5pdmVyc2l0eSBjb21wZW5zYXRpb24gdGhhdCBpcyBwYWlkIHRvIHRoZSB1bml2ZXJzaXR5IHByZXNpZGVudCwgd2UgY2FuIHNlZSB0aGF0IEhhbWxpbmUncyBwcmVzaWRlbnRpYWwgcG9ydGlvbiBoYXMgZ3Jvd24gc2l6YWJseSBzaW5jZSB0aGUgc3RhcnQgb2YgTWlsbGVyJ3MgcHJlc2lkZW5jeSwgbm90IG9ubHkgaW4gZXhjZXNzIG9mIHRoZSBNSUFDIGF2ZXJhZ2UgYnV0IGluIGNvbXBsZXRlIG9wcG9zaXRpb24gdG8gdGhlIGF2ZXJhZ2UgZGVjcmVhc2Ugc2VlbiBkdXJpbmcgdGhlIENPVklELTE5IHBhbmRlbWljLgoKIyMgQ2hhbmdlIGluIHRoZSBQcmVzaWRlbnRpYWwgUG9ydGlvbiBvZiBBbGwgQ29tcGVuc2F0aW9uLCBIYW1saW5lIHZzLiBNZWFuIGluIHRoZSBNSUFDCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTl9CiNwZGYoJ1ByZXNQYXlDaGFuZ2UucGRmJywgd2lkdGg9MTIsIGhlaWdodD05KQoKcGMgJT4lIGZpbHRlcihUaXRsZSAlaW4lIGMoIlBSRVNJREVOVCIsICJQcmVzaWRlbnQiKSwgIShTY2hvb2wgJWluJSBjKCJTdC4gTWFyeSIsICJTdC4gS2F0ZSIpKSkgJT4lIAogIG11dGF0ZShDb21wUmF0ZSA9IFJlcG9ydGFibGVDb21wRnJvbU9yZy8oT2ZmaWNlclBheSArIE90aGVyU2FsYXJpZXMpKSAlPiUgCiAgZ3JvdXBfYnkoaXNIVSwgWWVhcikgJT4lIHN1bW1hcml6ZShDb21wUmF0ZSA9IG1lYW4oQ29tcFJhdGUpKSAlPiUgYXJyYW5nZShZZWFyKSAlPiUKICBnZ3Bsb3QoYWVzKHg9WWVhciwgeT1Db21wUmF0ZSkpICsgZ2VvbV9saW5lKGFlcyhjb2xvcj1pc0hVKSwgbGluZXdpZHRoPTUpICsgcGN0ICsKICB0aGVtZV9taW5pbWFsKCkgKyBsYWJzKGNvbD0iIiwgeSA9ICJQcmVzaWRlbnRpYWwgcG9ydGlvbiBvZiBhbGwgdW5pdmVyc2l0eSBjb21wZW5zYXRpb24iKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTIwMTUsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgZ2VvbV90ZXh0KGFlcyh4PS05MDApLCB4PTIwMTUuMiwgeT0wLjAxNSwgbGFiZWw9IlByZXNpZGVudCBNaWxsZXIncyBGaXJzdCBUZXJtIiwgYW5nbGU9OTAsIGZhbWlseT0iQXZlbmlyIiwKICAgICAgICAgICAgc2l6ZT10ZXh0c3oqMC4yOCkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygyMDEyOjIwMjEpLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIicxMiIsICInMTMiLCAiJzE0IiwgIicxNSIsICInMTYiLCAiJzE3IiwgIicxOCIsICInMTkiLCAiJzIwIiwgIicyMSIpLCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoMjAxMiwgMjAyMSkpICsKICBndWlkZXMoY29sPWd1aWRlX2xlZ2VuZChucm93PTIsIGJ5cm93PVQpLCBsYWJlbCA9IEYsIHRleHQgPSBGLCBjb2w9RikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KCB2anVzdD0xKSwKICAgICAgICB0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IkF2ZW5pciIsIHNpemU9dGV4dHN6KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBzaXplPXRleHRzeioxLjIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUsIHZqdXN0PS00KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3Q9MSwgdmp1c3Q9MS40KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbj0icmlnaHQiLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKC01MCwgMywgMCwgMCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT10ZXh0c3oqMC45NSksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMjAsICJwdCIpCiAgICAgICAgKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhoYW1saW5lX3JlZCwgbWlhY19ncmVlbikpCgojZGV2Lm9mZigpCgpgYGAKCgojIE5vdGVzCg==